//
//  BlockViewController.m
//  iOSCodeLearning
//
//  Created by TFAppleWork-Summer on 2018/3/26.
//  Copyright © 2018年 Ace. All rights reserved.
//

#import "BlockViewController.h"
#import "TestPerson.h"
#import "CalculatorManager.h"

// 全局变量
int global_i = 1;

// 静态全局变量
static int static_global_j = 2;

typedef void(^propertyBlcok) (void);

@interface BlockViewController ()
@property (nonatomic, copy) NSString *str;

@property (nonatomic, copy) propertyBlcok copyBlock;

@property (nonatomic, strong) propertyBlcok strongBlock;

@property (nonatomic, copy) void(^name)(void);

@end

@implementation BlockViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    self.view.backgroundColor = [UIColor whiteColor];
    
    [self p_testCalculator];
//    static int static_k = 3;
//    int val = 4;
//    void (^myBlock)(void) = ^{
//        global_i ++; // 修改全局变量
//        static_global_j ++; // 修改静态全局变量
//        static_k ++;  // 修改静态变量
//        NSLog(@"Block中 global_i = %d,static_global_j = %d,static_k = %d,val = %d",global_i,static_global_j,static_k,val);
//    };
//
//    global_i ++; // 修改全局变量
//    static_global_j ++;  // 修改静态全局变量
//    static_k ++;   // 修改静态变量
//    val ++;
//    NSLog(@"Block外 global_i = %d,static_global_j = %d,static_k = %d,val = %d",global_i,static_global_j,static_k,val);
//
//    myBlock();
    
    /*
     局部变量是以值传递方式传递到Block的构造函数里面去的。
     Block只捕获Block中会用到的变量。
     由于只捕获了局部变量的值，并非内存地址，所以Block内部不能改变自动变量的值。
     Block捕获的外部变量可以改变值的是静态变量，静态全局变量，全局变量
     静态变量传递给Block是内存地址值，所以能在Block里面直接改变值。
     */
    
//    [TestPerson sharePerson];
//    TestPerson *person = [[TestPerson alloc] init];

}

-(void)p_testCalculator{
    CalculatorManager *mgr = [[CalculatorManager alloc] init];
//    [[[mgr add:5] add:5] add:5];
    mgr.add(5).add(5).add(5);
    
    [mgr add:^(int result) {
        result+=2;
        result+=5;
    }];
    
    
    NSLog(@"%d",mgr.result);
}

-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
    
    /*
     _NSConcreteStackBlock：(不持有对象)
     只用到外部局部变量、成员属性变量，且没有强指针引用的block都是StackBlock。
     StackBlock的生命周期由系统控制的，一旦返回之后，就被系统销毁了。
     _NSConcreteMallocBlock：(持有对象)
     有强指针引用或copy修饰的成员属性引用的block会被复制一份到堆中成为MallocBlock，没有强指针引用即销毁，生命周期由程序员控制
     _NSConcreteGlobalBlock：（不持有对象）
     没有用到外界变量或只用到全局变量、静态变量的block为_NSConcreteGlobalBlock，生命周期从创建到应用程序结束。
     */
    
    
//    [self stackBlock];
//    [self globalBlock];
    
//    [self __blockTest];
//    [self propetryBlockTest];
}

-(void)__blockTest{
    /*
     带有 __block的变量也被转化成了一个结构体__Block_byref_i_0,这个结构体有5个成员变量。
     第一个是isa指针，
     第二个是指向自身类型的__forwarding指针，
     第三个是一个标记flag，
     第四个是它的大小，
     第五个是变量值，名字和变量名同名
     */
    
     /*
      堆上的Block会持有对象。我们把Block通过copy到了堆上，堆上也会重新复制一份Block，并且该Block也会继续持有该__block。
      当Block释放的时候，__block没有被任何对象引用，也会被释放销毁。
      
      __forwarding指针这里的作用就是针对堆的Block，把原来__forwarding指针指向自己，换成指向_NSConcreteMallocBlock上复制之后的__block自己。然后堆上的变量的__forwarding再指向自己。这样不管__block怎么复制到堆上，还是在栈上，都可以通过(i->__forwarding->i)来访问到变量值。
      
      
      对于声明为__block的外部对象，在block内部会进行retain，以至于在block环境内能安全的引用外部对象。
      */
    __block int var = 10;
    __block NSString *string = @"111";
    NSMutableString * mutableString = [NSMutableString stringWithString:@"111"];
    // arc下经过赋值后会copy到堆区 __NSMallocBlock__
    void(^testBlock)(void) = ^{
        
        var = 11;
        // 将 指针“mutableString”传进block,修改的是指针“mutableString”所指向的值
        [mutableString appendString:@"2222"];
        // 修改指针 所指向的空间 需要使用__block
        string = @"222";
    };
    
    NSLog(@"%@",testBlock);
    
}


-(void)stackBlock{
    NSString *str = @"外部局部变量";
    self.str = @"成员属性变量";
    void (^stackBlock)(void) = ^{
        NSLog(@"%@",str);
    };
    // 像这样赋值后 然后打印会发现在  __NSMallocBlock__  在ARC环境下，编译器会自动的判断，把Block自动的从栈copy到堆
    NSLog(@"%@",stackBlock);
    // 这样不赋值直接打印  __NSMallocBlock__
    NSLog(@"%@",^{
        NSLog(@"%@",self.str);
    });
}

-(void)globalBlock{
    
    // __NSGlobalBlock__
    static int static_k = 3;
    void (^myBlock)(void) = ^{
        NSLog(@"Block中 变量 = %d %d %d",static_global_j ,static_k, global_i);
    };
    NSLog(@"%@",myBlock);

    myBlock();

}

-(void)propetryBlockTest{
    int var = 10;
    void (^myBlock)(void) = ^{
        NSLog(@"propetryBlockTest %d",var);
    };
    
    self.copyBlock = myBlock;
    self.strongBlock = myBlock;
    
    NSLog(@"myBlock:%@",myBlock);
    NSLog(@"copyBlock:%@",self.copyBlock);
    NSLog(@"strongBlock:%@",self.strongBlock);
    NSLog(@" 直接打印 %@", ^{
        NSLog(@"propetryBlockTest %d",var);
    });
    
}


- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
    
}


@end
